<?php
/**
 * Pagination Helper, responsible for managing the LINKS required for pagination.
 * ALL parameters are specified in the component.
 */
class PaginationHelper extends Helper {
	/**
	 * Options to be passed to ajax links if used
	 *
	 * @var array
	 * @access public
	 */
	var $ajaxLinkOptions = array ( );
	/**
	 * Placeholder for the link style - defined in/by the component
	 *
	 * @var boolean
	 * @access private
	 */
	var $style = 'html';
	/**
	 * Placeholder for the parameter style - defined in/by the component
	 *
	 * @var boolean
	 * @access private
	 */
	var $paramStyle = 'get';
	/**
	 * Placeholder for the pagination details
	 *
	 * @var array
	 * @access private
	 */
	var $_pageDetails = Array ( );
	/**
	 * Helpers
	 *
	 * @var array
	 * @access private
	 */
	var $helpers = Array ("Html", "Ajax" );
	
	/**
	 * Sets the default pagination options. Fails if the value $paging is not set
	 *
	 * @param array $paging an array detailing the page options
	 * @return boolean
	 */
	function setPaging($paging) {
		if (empty ( $paging )) {
			return false;
		}
		$this->_pageDetails = $paging;
		$this->_pageDetails ['previousPage'] = ($paging ['page'] > 1) ? $this->_pageDetails ['page'] - 1 : '';
		$this->_pageDetails ['nextPage'] = ($paging ['page'] < $this->_pageDetails ['pageCount']) ? $this->_pageDetails ['page'] + 1 : '';
		
		$this->url = $this->_pageDetails ['url'];
		
		$getParams = $this->params ['url'];
		unset ( $getParams ['url'] );
		$this->getParams = $getParams;
		
		$this->showLimits = $this->_pageDetails ['showLimits'];
		$this->style = isset ( $this->_pageDetails ['style'] ) ? $this->_pageDetails ['style'] : $this->style;
		
		if (($this->_pageDetails ['maxPages'] % 2) == 0) // need odd number of page links
{
			$this->_pageDetails ['maxPages'] = $this->_pageDetails ['maxPages'] - 1;
		}
		
		$this->maxPages = $this->_pageDetails ['maxPages'];
		$this->pageSpan = ($this->_pageDetails ['maxPages'] - 1) / 2;
		
		return true;
	}
	
	/**
	 * Displays the list of pages for the given parameters.
	 *
	 * @param string text to display before limits
	 * @param string display a separate between limits
	 * @param boolean whether to escape the title or not
	 * @return unknown the html string for modifying the number of results per page
	 **/
	function resultsPerPage($t = "Results per page: ", $separator = "  ", $escapeTitle = true) {
		if (empty ( $this->_pageDetails )) {
			return false;
		}
		$pageDetails = $this->_pageDetails;
		if (! empty ( $pageDetails ['pageCount'] )) {
			if (is_array ( $pageDetails ['resultsPerPage'] )) {
				$OriginalValue = $pageDetails ['show'];
				$t .= $separator;
				foreach ( $pageDetails ['resultsPerPage'] as $value ) {
					if ($OriginalValue == $value) {
						$t .= '<a style="color:red;">' . $value . '</a>' . $separator;
					} else {
						$pageDetails ['show'] = $value;
						$t .= $this->_generateLink ( $value, 1, $escapeTitle, $pageDetails ) . $separator;
					}
				}
			}
			return $t;
		}
		return false;
	}
	
	/**
	 * Generate a select box for options for results per page
	 *
	 * @param string prefix text
	 * @return unknown the html string for the select box for modifying the number of results per page
	 **/
	function resultsPerPageSelect($t = "Results per page: ") {
		if (empty ( $this->_pageDetails )) {
			return false;
		}
		if (! empty ( $this->_pageDetails ['pageCount'] )) {
			$Options = Array ( );
			if (is_array ( $this->_pageDetails ['resultsPerPage'] )) {
				foreach ( $this->_pageDetails ['resultsPerPage'] as $value ) {
					$Options [$value] = $value;
				}
			}
			return $t . $this->Html->selectTag ( "pagination/show", $Options, $this->_pageDetails ['show'], NULL, NULL, FALSE );
		}
		return false;
	}
	
	/**
	 * Displays info of the current result set
	 *
	 * @param string prefix text
	 * @param string
	 * @param string
	 * @return unknown the html string for the current result set.
	 **/
	function result($t = "当前:", $of = " /全部:", $inbetween = "-") {
	//function result($t = "", $of = " of ", $inbetween = "-") {
		if (empty ( $this->_pageDetails )) {
			return false;
		}
		if (! empty ( $this->_pageDetails ['pageCount'] )) {
			if ($this->_pageDetails ['pageCount'] > 1) {
				$start_row = (($this->_pageDetails ['page'] - 1) * $this->_pageDetails ['show']) + 1;
				$end_row = min ( (($this->_pageDetails ['page']) * $this->_pageDetails ['show']), ($this->_pageDetails ['total']) );
				$t = $t . $start_row . $inbetween . $end_row . $of . $this->_pageDetails ['total'];
			} else {
				$t .= $this->_pageDetails ['total'];
			}
			return $t;
		}
		return false;
	}
	/**
	 * Returns a list of page numbers separated by $separator
	 *
	 * @param string $separator - defaults to null
	 * @param boolean
	 * @param string $spacerLower - If there are more results than space for the links, the text inbetween
	 * @param string $spacerUpper - If there are more results than space for the links, the text inbetween
	 * @return string html for the list of page numbers
	 **/
	function pageNumbers($separator = null, $escapeTitle = true, $spacerLower = "<em.pagi>...</em>", $spacerUpper = "<em.pagi>...</em>") {
		if (empty ( $this->_pageDetails ) || $this->_pageDetails ['pageCount'] == 1) {
			return "<em.pagi>1</em>";
		}

		$total = $this->_pageDetails ['pageCount'];
		$max = $this->maxPages;
		$span = $this->pageSpan;
		if ($total < $max) {
			$upperLimit = min ( $total, ($span * 2 + 1) );
			$lowerLimit = 1;
		} elseif ($this->_pageDetails ['page'] < ($span + 1)) {
			$lowerLimit = 1;
			$upperLimit = min ( $total, ($span * 2 + 1) );
		} elseif ($this->_pageDetails ['page'] > ($total - $span)) {
			$upperLimit = $total;
			$lowerLimit = max ( 1, $total - $span * 2 );
		} else {
			$upperLimit = min ( $total, $this->_pageDetails ['page'] + $span );
			$lowerLimit = max ( 1, ($this->_pageDetails ['page'] - $span) );
		}
		
		$t = array ( );
		if (($lowerLimit != 1) and ($this->showLimits)) {
			$lowerLimit = $lowerLimit + 1;
			$t [] = "<span>".$this->_generateLink ( 1, 1, $escapeTitle )."</span>";
			if ($spacerLower) {
				$t [] = $spacerLower;
			}
		}
		if (($upperLimit != $total) and ($this->showLimits)) {
			$dottedUpperLimit = true;
		} else {
			$dottedUpperLimit = false;
		}
		if (($upperLimit != $total) and ($this->showLimits)) {
			$upperLimit = $upperLimit - 1;
		}
		for($i = $lowerLimit; $i <= $upperLimit; $i ++) {
			if ($i == $this->_pageDetails ['page']) {
				$text = '<em.pagi>' . $i . '</em>';
			} else {
				$text = "<span>" . $this->_generateLink ( $i, $i, $escapeTitle ) . "</span>";
			}
			$t [] = $text;
		}
		if ($dottedUpperLimit) {
			if ($spacerUpper) {
				$t [] = $spacerUpper;
			}
			$t [] = "<span>".$this->_generateLink ( $this->_pageDetails ['pageCount'], $this->_pageDetails ['pageCount'], $escapeTitle )."</span>";
		}
		$t = implode ( $separator, $t );
		return $t;
	}
	
	/**
	 * Displays a link to the previous page, where the page doesn't exist then
	 * display the $text
	 *
	 * @param string $text - text display: defaults to next
	 * @return string html for link/text for previous item
	 **/
	function prevPage($text = 'prev', $escapeTitle = true) {
		if (empty ( $this->_pageDetails )) {
			return false;
		}
		if (! empty ( $this->_pageDetails ['previousPage'] )) {
			return $this->_generateLink ( $text, $this->_pageDetails ['previousPage'], $escapeTitle );
		}
		return $text;
	}
	
	/**
	 * Displays a link to the next page, where the page doesn't exist then
	 * display the $text
	 *
	 * @param string $text - text to display: defaults to next
	 * @return string html for link/text for next item
	 **/
	function nextPage($text = 'next', $escapeTitle = true) {
		if (empty ( $this->_pageDetails )) {
			return false;
		}
		if (! empty ( $this->_pageDetails ['nextPage'] )) {
			return $this->_generateLink ( $text, $this->_pageDetails ['nextPage'], $escapeTitle );
		}
		return $text;
	}
	
	/**
	 * Displays a link to the first page
	 * display the $text
	 *
	 * @param string $text - text to display: defaults to next
	 * @return string html for link/text for next item
	 **/
	function firstPage($text = 'first', $escapeTitle = true) {
		if (empty ( $this->_pageDetails )) {
			return false;
		}
		if ($this->_pageDetails ['page'] != 1) {
			return $this->_generateLink ( $text, 1, $escapeTitle );
		} else {
			return false;
		}
	}
	
	/**
	 * Displays a link to the last page
	 * display the $text
	 *
	 * @param string $text - text to display: defaults to next
	 * @return string html for link/text for next item
	 **/
	function lastPage($text = 'last', $escapeTitle = true) {
		if (empty ( $this->_pageDetails )) {
			return false;
		}
		if ($this->_pageDetails ['page'] != $this->_pageDetails ['pageCount']) {
			return $this->_generateLink ( $text, $this->_pageDetails ['pageCount'], $escapeTitle );
		} else {
			return false;
		}
	}
	
	/**
	 * Generate link to sort the results by the given value
	 *
	 * @param string field to sort by
	 * @param string title for link defaults to $value
	 * @param string model to sort by - uses the default model class if absent
	 * @param boolean escape title
	 * @param string text to append to links to indicate sorted ASC
	 * @param string text to append to links to indicate sorted DESC
	 * @return string html for link to modify sort order
	 **/
	function sortBy($value, $title = NULL, $Model = NULL, $escapeTitle = true, $upText = " ^", $downText = " v") {
		if (empty ( $this->_pageDetails )) {
			return false;
		}
		$title = $title ? $title : ucfirst ( $value );
		$value = strtolower ( $value );
		$Model = $Model ? $Model : $this->_pageDetails ['Defaults'] ['sortByClass'];
		
		$OriginalSort = $this->_pageDetails ['sortBy'];
		$OriginalModel = $this->_pageDetails ['sortByClass'];
		$OriginalDirection = $this->_pageDetails ['direction'];
		
		if (($value == $OriginalSort) && ($Model == $OriginalModel)) {
			if (up ( $OriginalDirection ) == "DESC") {
				$this->_pageDetails ['direction'] = "ASC";
				$title .= $upText;
			} else {
				$this->_pageDetails ['direction'] = "DESC";
				$title .= $downText;
			}
		} else {
			if ($Model) {
				$this->_pageDetails ['sortByClass'] = $Model;
				//echo "page details model class set to ".$this->_pageDetails['sortByClass']."<br>";
			} else {
				$this->_pageDetails ['sortByClass'] = NULL;
			}
			$this->_pageDetails ['sortBy'] = $value;
		}
		$link = $this->_generateLink ( $title, 1, $escapeTitle );
		$this->_pageDetails ['sortBy'] = $OriginalSort;
		$this->_pageDetails ['sortByClass'] = $OriginalModel;
		$this->_pageDetails ['direction'] = $OriginalDirection;
		return $link;
	}
	
	/**
	 * Generate a select box for options to sort results
	 *
	 * @param array array of text strings, formatted as "Field::Direction::Class".
	 * @param string prefix text
	 * @param string text to append to links to indicate sorted ASC
	 * @param string text to append to links to indicate sorted DESC
	 * @return unknown the html string for the select box for selecting sort order
	 **/
	function sortBySelect($sortFields, $t = "Sort By: ", $upText = " ^", $downText = " v") {
		if (empty ( $this->_pageDetails )) {
			return false;
		}
		if (! empty ( $this->_pageDetails ['pageCount'] )) {
			$OriginalValue = $this->_pageDetails ['sortBy'] . "::" . $this->_pageDetails ['direction'] . "::" . $this->_pageDetails ['sortByClass'];
			if (is_array ( $sortFields )) {
				foreach ( $sortFields as $value ) {
					$Vals = Array ( );
					$Vals = explode ( "::", $value );
					if (isset ( $Vals [2] )) {
						$DisplayVal = $Vals [2] . " ";
					} else {
						$DisplayVal = "";
					}
					$DisplayVal .= $Vals [0];
					if (up ( $Vals [1] ) == "ASC") {
						$DisplayVal .= $downText;
					} else {
						$DisplayVal .= $upText;
					}
					$Options [$value] = $DisplayVal;
				}
				return $t . $this->Html->selectTag ( "pagination/sortByComposite", $Options, $OriginalValue, NULL, NULL, FALSE );
			}
		}
		return false;
	}
	
	/**
	 * Internal method to generate links based upon passed parameters.
	 *
	 * @param string title for link
	 * @param string page the page number
	 * @param boolean escape title
	 * @param string the div to be updated by AJAX updates
	 * @return string html for link
	 **/
	function _generateLink($title, $page = NULL, $escapeTitle, $pageDetails = NULL) {
		$pageDetails = $pageDetails ? $pageDetails : $this->_pageDetails;
		$url = $this->_generateUrl ( $page, $pageDetails );
		$AjaxDivUpdate = $pageDetails ['ajaxDivUpdate'];
		if ($this->style == "ajax") {
			$options = am ( $this->ajaxLinkOptions, array ("update" => $pageDetails ['ajaxDivUpdate'] ) );
			if (isset ( $pageDetails ['ajaxFormId'] )) {
				$id = 'link' . intval ( rand () );
				$return = $this->Html->link ( $title, $url, array ('id' => $id, 'onclick' => " return false;" ), NULL, $escapeTitle );
				$options ['with'] = "Form.serialize('{$this->_pageDetails['ajaxFormId']}')";
				$options ['url'] = $url;
				$return .= $this->Ajax->Javascript->event ( "'$id'", "click", $this->Ajax->remoteFunction ( $options ) );
				return $return;
			} else {
				return $this->Ajax->link ( $title, $url, $options, NULL, NULL, $escapeTitle );
			}
		} else {
			return $this->Html->link ( $title, $url, NULL, NULL, $escapeTitle );
		}
	}
	
	function _generateUrl($page = NULL, $pageDetails = NULL) {
		$pageDetails = $pageDetails ? $pageDetails : $this->_pageDetails;
		$getParams = $this->getParams; // Import any other pre-existing get parameters
		if ($this->_pageDetails ['paramStyle'] == "pretty") {
			$pageParams = $pageDetails ['importParams'];
		}
		$pageParams ['show'] = $pageDetails ['show'];
		$pageParams ['sortBy'] = $pageDetails ['sortBy'];
		$pageParams ['direction'] = $pageDetails ['direction'];
		$pageParams ['page'] = $page ? $page : $pageDetails ['page'];
		if (isset ( $pageDetails ['sortByClass'] )) {
			$pageParams ['sortByClass'] = $pageDetails ['sortByClass'];
		}
		$getString = Array ( );
		$prettyString = Array ( );
		if ($pageDetails ['paramStyle'] == "get") {
			$getParams = am ( $getParams, $pageParams );
		} else {
			foreach ( $pageParams as $key => $value ) {
				if (isset ( $pageDetails ['Defaults'] [$key] )) {
					if (up ( $pageDetails ['Defaults'] [$key] ) != up ( $value )) {
						$prettyString [] = "$key{$pageDetails['paramSeperator']}$value";
					}
				} else {
					$prettyString [] = "$key{$pageDetails['paramSeperator']}$value";
				}
			}
		}
		foreach ( $getParams as $key => $value ) {
			if ($pageDetails ['paramStyle'] == "get") {
				if (isset ( $pageDetails ['Defaults'] [$key] )) {
					if (up ( $pageDetails ['Defaults'] [$key] ) != up ( $value )) {
						$getString [] = "$key=$value";
					}
				} else {
					$getString [] = "$key=$value";
				}
			} else {
				$getString [] = "$key=$value";
			}
		}
		$url = $this->url;
		if ($prettyString) {
			$prettyString = implode ( "/", $prettyString );
			$url .= $prettyString;
		}
		if ($getString) {
			$getString = implode ( "&", $getString );
			$url .= "?" . $getString;
		}
		return $url;
	}
	
	/** 
	 * Displays page navigation links 
	 * 
	 * @param string $html list of page numbers  
	 *       (as generated by PaginationHelper::pageNumbers) 
	 * @param string $prev text (or html) to put in link to previous page 
	 * @param string $next text (or html) to put in link to next page 
	 * @param boolean $escape_text indicates whether we escape html entities of 
	 *        prev and next. 
	 * @return string the html for page navigation links. 
	 **/
	function nav($pages, $first = null, $prev = null, $next = null, $last = null, $escape_text = true) {
		$nav = '';
		if ($this->_pageDetails ['total'] > $this->_pageDetails ['show']) {
			//tomi	
			$f = "<span>".$this->firstPage ( $first, $escape_text )."</span>";
			$prev = "<span>".$this->prevPage ( $prev, $escape_text )."</span>";
			$next = "<span>".$this->nextPage ( $next, $escape_text )."</span>";
			$l = "<span>".$this->lastPage ( $last, $escape_text )."</span>";
			//end  
			
			if ($this->_pageDetails ['page'] > 1) {
				$nav .= $f . $prev . " ";
			}
			$nav .= $pages;
			$npages = ( int ) ($this->_pageDetails ['total'] / $this->_pageDetails ['show']);
			$r = $this->_pageDetails ['total'] % $this->_pageDetails ['show'];
			if ($r) {
				$npages ++;
			}
			if ($this->_pageDetails ['page'] < $npages) {
				$nav .= " " . $next . $l;
			}
		}
		return $nav;
	}


}
?>
